package com.photoeditor.demo.ui.widget;

import android.content.Context;
import android.support.v4.view.GestureDetectorCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;

import com.common.base.utils.DeviceUtils;

public class DragLayout extends FrameLayout {

    private GestureDetectorCompat mGestureDetector;
    private ViewDragHelper mDragHelper;
    private DragListener mDragListener;

    /**
     * 水平可以滚动的范围
     */
    private int mHorizontalRange;
    /**
     * 垂直可以滚动的范围
     */
    private int mVerticalRange;
    /**
     * 默认滚动是垂直的
     */
    private Orientation mOrientation = Orientation.Vertical;

    private int mViewWidth;
    private int mViewHeight;
    private int mDistanceLeft;
    private int mDistanceTop;

    private ViewGroup mEntranceLayout;
    private RecyclerView mRecyclerView;

    private Status mStatus = Status.Open;

    private boolean mCanDrag = true;
    private boolean mIsTop = true;

    public DragLayout(Context context) {
        this(context, null);
    }

    public DragLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public DragLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        mGestureDetector = new GestureDetectorCompat(context,
                new XYScrollDetector());
        mDragHelper = ViewDragHelper.create(this, dragHelperCallback);
    }

    class XYScrollDetector extends GestureDetector.SimpleOnGestureListener {
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float dx,
                                float dy) {
            if (mOrientation == Orientation.Vertical) {
                return Math.abs(dy) >= Math.abs(dx);
            }
            return Math.abs(dy) <= Math.abs(dx);
        }
    }

    private ViewDragHelper.Callback dragHelperCallback = new ViewDragHelper.Callback() {

        // 这个是返回被横向移动的子控件child的左坐标left，和移动距离dx，我们可以根据这些值来返回child的新的left。
        // 这个方法必须重写，要不然就不能移动了。
        // 返回横向坐标左右边界值
        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {

            if (mOrientation == Orientation.Vertical) {
                return 0;
            }
            if (mDistanceLeft + dx < 0) {
                // 右边界
                return 0;
            } else if (mDistanceLeft + dx > mHorizontalRange) {
                // 左边界
                return mHorizontalRange;
            } else {
                // 左右边界范围内
                return left;
            }
        }

        // 这个方法用来返回可以被移动的View对象，我们可以通过判断child与我们想移动的View是的相等来控制谁能移动。
        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            return true;
        }

        // 横向的边界范围
        @Override
        public int getViewHorizontalDragRange(View child) {
            return mHorizontalRange;
        }

        @Override
        public int clampViewPositionVertical(View child, int top, int dy) {

            if (mOrientation == Orientation.Horizontal) {
                return 0;
            }
            if (mDistanceTop + dy < 0) {
                return 0;
            } else if (mDistanceTop + dy > mVerticalRange) {
                return mVerticalRange;
            } else {
                return top;
            }
        }

        @Override
        public int getViewVerticalDragRange(View child) {
            return mVerticalRange;
        }

        // ACTION_UP事件后调用其方法
        // 当releasedChild被释放的时候，xvel和yvel是x和y方向的加速度
        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            super.onViewReleased(releasedChild, xvel, yvel);
            if (mOrientation == Orientation.Vertical) {
                if (releasedChild == mEntranceLayout) {
                    return;
                }
                if (yvel > 0) {
                    // 加速度向下
                    open();
                } else if (yvel < 0) {
                    // 加速度向上
                    close();
                } else if (releasedChild == mRecyclerView
                        && mDistanceTop > mVerticalRange * 0.3) {
                    // 如果释放时，手指在内容区且内容区离左边的距离是range * 0.3
                    open();
                } else {
                    close();
                }

            } else {
                if (xvel > 0) {
                    // 加速度向
                    open();
                } else if (xvel < 0) {
                    // 加速度向左
                    close();
                } else if (releasedChild == mRecyclerView
                        && mDistanceLeft > mHorizontalRange * 0.3) {
                    // 如果释放时，手指在内容区且内容区离左边的距离是range * 0.3
                    open();
                } else if (releasedChild == mEntranceLayout
                        && mDistanceLeft > mHorizontalRange * 0.7) {
                    // 如果释放时，手指在菜单区且内容区离左边的距离是range * 0.7
                    open();
                } else {
                    close();
                }
            }

        }

        // view在拖动过程坐标发生变化时会调用此方法，包括两个时间段：手动拖动和自动滚动
        @Override
        public void onViewPositionChanged(View changedView, int left, int top,
                                          int dx, int dy) {

            if (mOrientation == Orientation.Horizontal) {
                if (changedView == mRecyclerView) {
                    mDistanceLeft = left;
                } else {
                    mDistanceLeft = mDistanceLeft + left;
                }
                if (mDistanceLeft < 0) {
                    mDistanceLeft = 0;
                } else if (mDistanceLeft > mHorizontalRange) {
                    mDistanceLeft = mHorizontalRange;
                }
                mEntranceLayout.layout(0, 0, mViewWidth, mViewHeight);
                mRecyclerView.layout(mDistanceLeft, 0, mDistanceLeft + mViewWidth,
                        mViewHeight);
                dispatchDragEvent(mDistanceLeft);
            } else {
                mDistanceTop = top;
                if (mDistanceTop < 0) {
                    mDistanceTop = 0;
                } else if (mDistanceTop > mVerticalRange) {
                    mDistanceTop = mVerticalRange;
                }
                mEntranceLayout.layout(0, 0, mViewWidth, mViewHeight);
                mRecyclerView.layout(0, mDistanceTop, mViewWidth, mDistanceTop
                        + mViewHeight);
                dispatchDragEvent(mDistanceTop);
            }
        }
    };

    public interface DragListener {

        /**
         * 已经打开
         */
        void onOpen();

        /**
         * 已经关闭
         */
        void onClose();

        /**
         * 正在拖拽
         */
        void onDrag(float percent);

    }

    public void setDragListener(DragListener dragListener) {
        this.mDragListener = dragListener;
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        mEntranceLayout = (ViewGroup) getChildAt(0);
        mRecyclerView = (RecyclerView) getChildAt(1);
        mEntranceLayout.setClickable(true);
        mRecyclerView.setClickable(true);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mViewWidth = DeviceUtils.getScreenWidthPx();
        mViewHeight = mEntranceLayout.getMeasuredHeight();
        mHorizontalRange = mViewWidth * 1;
        mVerticalRange = DeviceUtils.dip2px(/*150*/440);
        mDistanceTop = mVerticalRange;
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right,
                            int bottom) {
        mEntranceLayout.layout(0, 0, mViewWidth, mViewHeight);
        if (mOrientation == Orientation.Horizontal) {
            mRecyclerView.layout(mDistanceLeft, 0, mDistanceLeft + mViewWidth,
                    mViewHeight);
        } else {
            mRecyclerView.layout(0, mDistanceTop, mViewWidth, mDistanceTop
                    + mViewHeight);
        }

    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (!mIsTop) {
            return false;
        }
        if (mCanDrag) {
            return mDragHelper.shouldInterceptTouchEvent(ev) && mGestureDetector.onTouchEvent(ev);
        } else {
            return false;
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent e) {
        try {

            // 在processTouchEvent中对ACTION_DOWN、ACTION_MOVE和ACTION_UP事件进行了处理：
            // 1.在ACTION_DOWN中调用回调接口中的tryCaptureView方法，看当前touch的view是否允许拖动
            // 在此项目中的是直接return true，两个view都是允许拖动的
            // 2.在ACTION_MOVE中，view的坐标发生改变，调用回调接口中的onViewPositionChanged方法，
            // 根据坐标信息对view进行layout，通过ViewHelper这个类中的setScaleX、setScaleY方法，实现在
            // 拖动的过程中view在XY坐标上进行相应比例的缩放；
            // 3.在ACTION_UP后调用回调接口中的onViewReleased方法，此方法中一个重要的任务是在ACTION_UP事件
            mDragHelper.processTouchEvent(e);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return false;
    }

    private void dispatchDragEvent(int mainLeft) {
        float percent;
        if (mOrientation == Orientation.Horizontal) {
            percent = mainLeft / (float) mHorizontalRange;
        } else {
            percent = mainLeft / (float) mVerticalRange;
        }

        Status lastStatus = mStatus;
        if (mDragListener == null) {
            return;
        }
        mDragListener.onDrag(percent);
        if (lastStatus != getStatus() && mStatus == Status.Close) {
            mDragListener.onClose();
        } else if (lastStatus != getStatus() && mStatus == Status.Open) {
            mDragListener.onOpen();
        }
    }

    @Override
    public void computeScroll() {
        if (mDragHelper.continueSettling(true)) {
            ViewCompat.postInvalidateOnAnimation(this);
        }
    }

    public enum Status {
        Drag, Open, Close
    }

    public enum Orientation {
        Horizontal, Vertical
    }

    public Status getStatus() {
        if (mOrientation == Orientation.Horizontal) {
            if (mDistanceLeft == 0) {
                mStatus = Status.Close;
            } else if (mDistanceLeft == mHorizontalRange) {
                mStatus = Status.Open;
            } else {
                mStatus = Status.Drag;
            }
        } else {
            if (mDistanceTop == 0) {
                mStatus = Status.Close;
            } else if (mDistanceTop == mVerticalRange) {
                mStatus = Status.Open;
            } else {
                mStatus = Status.Drag;
            }
        }

        return mStatus;
    }

    public RecyclerView getRecyclerView() {
        return mRecyclerView;
    }

    public ViewGroup getEntranceLayout() {
        return mEntranceLayout;
    }

    public void setOrientation(Orientation orientation) {
        this.mOrientation = orientation;
    }

    public void open() {
        open(true);
//        StatisticsUtils.statisticGrowingIo(StatisticsConstant.EVENT_MAIN_PAGE_SHOW, StatisticsConstant.KEY_MAIN_PAGE_FUN,
//                StatisticsConstant.MAIN_PAGE_VALUE_EDIT);
//        StatisticsUtils.statisticGrowingIo(StatisticsConstant.EVENT_MAIN_PAGE_SHOW, StatisticsConstant.KEY_MAIN_PAGE_FUN,
//                StatisticsConstant.MAIN_PAGE_VALUE_CAMERA);
//        StatisticsUtils.statisticGrowingIo(StatisticsConstant.EVENT_MAIN_PAGE_SHOW, StatisticsConstant.KEY_MAIN_PAGE_FUN,
//                StatisticsConstant.MAIN_PAGE_VALUE_PREMIUM);
    }

    public void open(boolean animate) {
        if (animate) {
            if (mOrientation == Orientation.Horizontal) {
                if (mDragHelper.smoothSlideViewTo(mRecyclerView,
                        mHorizontalRange, 0)) {
                    ViewCompat.postInvalidateOnAnimation(this);
                }
            } else {
                if (mDragHelper.smoothSlideViewTo(mRecyclerView, 0,
                        mVerticalRange)) {
                    ViewCompat.postInvalidateOnAnimation(this);
                }
            }
        } else {
            mRecyclerView.layout(mHorizontalRange, 0, mHorizontalRange
                    + mViewWidth, mViewHeight);
            dispatchDragEvent(mHorizontalRange);
        }
    }

    public void close() {
        close(true);
    }

    public void close(boolean animate) {
        if (animate) {

            if (mDragHelper.smoothSlideViewTo(mRecyclerView, 0, 0)) {
                ViewCompat.postInvalidateOnAnimation(this);
            }
        } else {
            mRecyclerView.layout(0, 0, mViewWidth, mViewHeight);
            dispatchDragEvent(0);
        }
    }

    public void setCanDrag(boolean canDrag) {
        mCanDrag = canDrag;
    }

    public void setIsTop(boolean isTop) {
        mIsTop = isTop;
    }

}